home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1999 March / EnigmA AMIGA RUN 35 (1999)(G.R. Edizioni)(IT)[!][issue 1999-03].iso / earcd / devel / vbcc-68k-src / machines / amiga68k / libsrc / stdio / vfprintf.c < prev    next >
C/C++ Source or Header  |  1999-01-01  |  11KB  |  380 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <stdarg.h>
  4. #include <limits.h>
  5. #include <ctype.h>
  6. #include <math.h>
  7. #include <float.h>
  8.  
  9. /* a little macro to make life easier */
  10.  
  11. #define OUT(c)  do                           \
  12.                 { if(putc((c),stream)==EOF) \
  13.                     return outcount;         \
  14.                   outcount++;                \
  15.                 }while(0)
  16.  
  17. #define BITSPERBYTE CHAR_BIT
  18.  
  19. #define MINFLOATSIZE (DBL_DIG+1) /* Why not 1 more - it's 97% reliable */
  20. #define MININTSIZE (sizeof(unsigned long)*BITSPERBYTE/3+1)
  21. #define MINPOINTSIZE (sizeof(void *)*BITSPERBYTE/4+1)
  22. #define REQUIREDBUFFER (MININTSIZE>MINPOINTSIZE? \
  23.                         (MININTSIZE>MINFLOATSIZE?MININTSIZE:MINFLOATSIZE): \
  24.                         (MINPOINTSIZE>MINFLOATSIZE?MINPOINTSIZE:MINFLOATSIZE))
  25.  
  26. #define ALTERNATEFLAG 1  /* '#' is set */
  27. #define ZEROPADFLAG   2  /* '0' is set */
  28. #define LALIGNFLAG    4  /* '-' is set */
  29. #define BLANKFLAG     8  /* ' ' is set */
  30. #define SIGNFLAG      16 /* '+' is set */
  31.  
  32.  
  33. int vfprintf(FILE *stream,const char *format,va_list args)
  34. {
  35.   size_t outcount=0;
  36.  
  37.   while(*format)
  38.   {
  39.     if(*format=='%')
  40.     {
  41.       static char flagc[]=
  42.       { '#','0','-',' ','+' };
  43.       static char lowertabel[]=
  44.       { '0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f' };
  45.       static char uppertabel[]=
  46.       { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
  47.       size_t width=0,preci=ULONG_MAX,flags=0; /* Specifications */
  48.       char type,subtype='i';
  49.       char buffer1[2];             /* Signs and that like */
  50.       char buffer[REQUIREDBUFFER]; /* The body */
  51.       char *buffer2=buffer;        /* So we can set this to any other strings */
  52.       size_t size1=0,size2=0;      /* How many chars in buffer? */
  53.       const char *ptr=format+1;    /* pointer to format string */
  54.       size_t i,pad;                /* Some temporary variables */
  55.  
  56.       do /* read flags */
  57.         for(i=0;i<sizeof(flagc);i++)
  58.           if(flagc[i]==*ptr)
  59.           { flags|=1<<i;
  60.             ptr++;
  61.             break; }
  62.       while(i<sizeof(flagc));
  63.  
  64.       if(*ptr=='*') /* read width from arguments */
  65.       { signed int a;
  66.         ptr++;
  67.         a=va_arg(args,signed int);
  68.         if(a<0)
  69.         { flags|=LALIGNFLAG;
  70.           width=-a; }
  71.         else
  72.           width=a;
  73.       }else
  74.         while(isdigit(*ptr))
  75.           width=width*10+(*ptr++-'0');
  76.  
  77.       if(*ptr=='.')
  78.       { ptr++;
  79.         if(*ptr=='*') /* read precision from arguments */
  80.         { signed int a;
  81.           ptr++;
  82.           a=va_arg(args,signed int);
  83.           if(a>=0)
  84.             preci=a;
  85.         }else
  86.         { preci=0;
  87.           while(isdigit(*ptr))
  88.             preci=preci*10+(*ptr++-'0');
  89.         }
  90.       }
  91.  
  92.       if(*ptr=='h'||*ptr=='l'||*ptr=='L')
  93.         subtype=*ptr++;
  94.  
  95.       type=*ptr++;
  96.  
  97.       switch(type)
  98.       { case 'd':
  99.         case 'i':
  100.         case 'o':
  101.         case 'p':
  102.         case 'u':
  103.         case 'x':
  104.         case 'X':
  105.         { unsigned long v;
  106.           char *tabel;
  107.           int base;
  108.  
  109.           if(type=='p')
  110.           { subtype='l'; /* This is written as %#lx */
  111.             type='x';
  112.             flags|=ALTERNATEFLAG; }
  113.  
  114.           if(type=='d'||type=='i') /* These are signed */
  115.           { signed long v2;
  116.             if(subtype=='l')
  117.               v2=va_arg(args,signed long);
  118.             else
  119.               v2=va_arg(args,signed int);
  120.             if(v2<0)
  121.             { buffer1[size1++]='-';
  122.               v=-v2;
  123.             }else
  124.             { if(flags&SIGNFLAG)
  125.                 buffer1[size1++]='+';
  126.               else if(flags&BLANKFLAG)
  127.                 buffer1[size1++]=' ';
  128.               v=v2; }
  129.           }else                    /* These are unsigned */
  130.           { if(subtype=='l')
  131.               v=va_arg(args,unsigned long);
  132.             else
  133.               v=va_arg(args,unsigned int);
  134.             if(flags&ALTERNATEFLAG)
  135.             { if(type=='o'&&(preci||v))
  136.                 buffer1[size1++]='0';
  137.               if((type=='x'||type=='X')&&v)
  138.               { buffer1[size1++]='0';
  139.                 buffer1[size1++]=type; }
  140.             }
  141.           }
  142.  
  143.           buffer2=&buffer[sizeof(buffer)]; /* Calculate body string */
  144.           base=type=='x'||type=='X'?16:(type=='o'?8:10);
  145.           tabel=type!='X'?lowertabel:uppertabel;
  146.           do
  147.           { *--buffer2=tabel[v%base];
  148.             v=v/base;
  149.             size2++;
  150.           }while(v);
  151.           if(preci==ULONG_MAX) /* default */
  152.             preci=0;
  153.           else
  154.             flags&=~ZEROPADFLAG;
  155.           break;
  156.         }
  157.         case 'c':
  158.           if(subtype=='l')
  159.             *buffer2=va_arg(args,long);
  160.           else
  161.             *buffer2=va_arg(args,int);
  162.           size2=1;
  163.           preci=0;
  164.           break;
  165.         case 's':
  166.           buffer2=va_arg(args,char *);
  167.           { char *p=buffer2;
  168.             size2=0;
  169.             while((preci<=0||size2<preci)&&*p){size2++;p++;}
  170.           }
  171.           preci=0;
  172.           break;
  173. #ifdef MATH
  174.         case 'f':
  175.         case 'e':
  176.         case 'E':
  177.         case 'g':
  178.         case 'G':
  179.         { double v;
  180.           char killzeros=0,sign=0; /* some flags */
  181.           int ex1,ex2; /* Some temporary variables */
  182.           size_t size,dnum,dreq;
  183.           char *udstr=NULL;
  184.  
  185.           v=va_arg(args,double);
  186.  
  187.           if(isinf(v))
  188.           { if(v>0)
  189.               udstr="+inf";
  190.             else
  191.               udstr="-inf";
  192.           }else if(isnan(v))
  193.             udstr="NaN";
  194.  
  195.           if(udstr!=NULL)
  196.           { size2=strlen(udstr);
  197.             preci=0;
  198.             buffer2=udstr;
  199.             break; }
  200.  
  201.           if(preci==ULONG_MAX) /* old default */
  202.             preci=6; /* new default */
  203.  
  204.           if(v<0.0)
  205.           { sign='-';
  206.             v=-v;
  207.           }else
  208.           { if(flags&SIGNFLAG)
  209.               sign='+';
  210.             else if(flags&BLANKFLAG)
  211.               sign=' ';
  212.           }
  213.  
  214.           ex1=0;
  215.           if(v!=0.0)
  216.           { ex1=log10(v);
  217.             if(v<1.0)
  218.               v=v*pow(10,- --ex1); /* Caution: (int)log10(.5)!=-1 */
  219.             else
  220.               v=v/pow(10,ex1);
  221.             if(v<1.0) /* adjust if we are too low (log10(.1)=-.999999999) */
  222.             { v*=10.0; /* luckily this cannot happen with FLT_MAX and FLT_MIN */
  223.               ex1--; } /* The case too high (log(10.)=.999999999) is done later */
  224.           }
  225.  
  226.           ex2=preci;
  227.           if(type=='f')
  228.             ex2+=ex1;
  229.           if(tolower(type)=='g')
  230.             ex2--;
  231.           v+=.5/pow(10,ex2<MINFLOATSIZE?ex2:MINFLOATSIZE); /* Round up */
  232.  
  233.           if(v>=10.0) /* Adjusts log10(10.)=.999999999 too */
  234.           { v/=10.0;
  235.             ex1++; }
  236.  
  237.           if(tolower(type)=='g') /* This changes to one of the other types */
  238.           { if(ex1<(signed long)preci&&ex1>=-4)
  239.             { type='f';
  240.               preci-=ex1;
  241.             }else
  242.               type=type=='g'?'e':'E';
  243.             preci--;
  244.             if(!(flags&ALTERNATEFLAG))
  245.               killzeros=1; /* set flag to kill trailing zeros */
  246.           }
  247.  
  248.           dreq=preci+1; /* Calculate number of decimal places required */
  249.           if(type=='f')
  250.             dreq+=ex1;   /* even more before the decimal point */
  251.  
  252.           dnum=0;
  253.           while(dnum<dreq&&dnum<MINFLOATSIZE) /* Calculate all decimal places needed */
  254.           { buffer[dnum++]=(char)v+'0';
  255.             v=(v-(double)(char)v)*10.0; }
  256.  
  257.           if(killzeros) /* Kill trailing zeros if possible */
  258.             while(preci&&(dreq-->dnum||buffer[dreq]=='0'))
  259.               preci--;
  260.  
  261.           if(type=='f')/* Calculate actual size of string (without sign) */
  262.           { size=preci+1; /* numbers after decimal point + 1 before */
  263.             if(ex1>0)
  264.               size+=ex1; /* numbers >= 10 */
  265.             if(preci||flags&ALTERNATEFLAG)
  266.               size++; /* 1 for decimal point */
  267.           }else
  268.           { size=preci+5; /* 1 for the number before the decimal point, and 4 for the exponent */
  269.             if(preci||flags&ALTERNATEFLAG)
  270.               size++;
  271.             if(ex1>99||ex1<-99)
  272.               size++; /* exponent needs an extra decimal place */
  273.           }
  274.  
  275.           pad=size+(sign!=0);
  276.           pad=pad>=width?0:width-pad;
  277.  
  278.           if(sign&&flags&ZEROPADFLAG)
  279.             OUT(sign);
  280.  
  281.           if(!(flags&LALIGNFLAG))
  282.             for(i=0;i<pad;i++)
  283.               OUT(flags&ZEROPADFLAG?'0':' ');
  284.  
  285.           if(sign&&!(flags&ZEROPADFLAG))
  286.             OUT(sign);
  287.  
  288.           dreq=0;
  289.           if(type=='f')
  290.           { if(ex1<0)
  291.               OUT('0');
  292.             else
  293.               while(ex1>=0)
  294.               { OUT(dreq<dnum?buffer[dreq++]:'0');
  295.                 ex1--; }
  296.             if(preci||flags&ALTERNATEFLAG)
  297.             { OUT('.');
  298.               while(preci--)
  299.                 if(++ex1<0)
  300.                   OUT('0');
  301.                 else
  302.                   OUT(dreq<dnum?buffer[dreq++]:'0');
  303.             }
  304.           }else
  305.           { OUT(buffer[dreq++]);
  306.             if(preci||flags&ALTERNATEFLAG)
  307.             { OUT('.');
  308.               while(preci--)
  309.                 OUT(dreq<dnum?buffer[dreq++]:'0');
  310.             }
  311.             OUT(type);
  312.             if(ex1<0)
  313.             { OUT('-');
  314.               ex1=-ex1; }
  315.             else
  316.               OUT('+');
  317.             if(ex1>99)
  318.               OUT(ex1/100+'0');
  319.             OUT(ex1/10%10+'0');
  320.             OUT(ex1%10+'0');
  321.           }
  322.  
  323.           if(flags&LALIGNFLAG)
  324.             for(i=0;i<pad;i++)
  325.               OUT(' ');
  326.  
  327.           width=preci=0; /* Everything already done */
  328.           break;
  329.         }
  330. #endif
  331.         case '%':
  332.           buffer2="%";
  333.           size2=1;
  334.           preci=0;
  335.           break;
  336.         case 'n':
  337.           *va_arg(args,int *)=outcount;
  338.           width=preci=0;
  339.           break;
  340.         default:
  341.           if(!type)
  342.             ptr--; /* We've gone too far - step one back */
  343.           buffer2=(char *)format;
  344.           size2=ptr-format;
  345.           width=preci=0;
  346.           break;
  347.       }
  348.       pad=size1+(size2>=preci?size2:preci); /* Calculate the number of characters */
  349.       pad=pad>=width?0:width-pad; /* and the number of resulting pad bytes */
  350.  
  351.       if(flags&ZEROPADFLAG) /* print sign and that like */
  352.         for(i=0;i<size1;i++)
  353.           OUT(buffer1[i]);
  354.  
  355.       if(!(flags&LALIGNFLAG)) /* Pad left */
  356.         for(i=0;i<pad;i++)
  357.           OUT(flags&ZEROPADFLAG?'0':' ');
  358.  
  359.       if(!(flags&ZEROPADFLAG)) /* print sign if not zero padded */
  360.         for(i=0;i<size1;i++)
  361.           OUT(buffer1[i]);
  362.  
  363.       for(i=size2;i<preci;i++) /* extend to precision */
  364.         OUT('0');
  365.  
  366.       for(i=0;i<size2;i++) /* print body */
  367.         OUT(buffer2[i]);
  368.  
  369.       if(flags&LALIGNFLAG) /* Pad right */
  370.         for(i=0;i<pad;i++)
  371.           OUT(' ');
  372.  
  373.       format=ptr;
  374.     }
  375.     else
  376.       OUT(*format++);
  377.   }
  378.   return outcount;
  379. }
  380.